/************************************************************************************************************************************************************
*                          DESENVOLVEDORES: Paulo Costa; Diogo Oliveira; Iara Fernanda; Mariana Souza
*                          ORIENTADOR e CO-DESENVOLVEDOR: Prof.Dr. Eraldo Pereira Marinho
*
*                                                           ARQUIVO: parser.c
*
************************************************************************************************************************************************************/

/** 
 * Simplified Pascal in the EBNF:
 * 
 * program -> PROGRAM ID ';' block '.'
 * 
 * block -> declarations modules stmtblock  -- NAO EXISTE MAIS PROCEDURE DENTRO DE PROCEDURE
 * 
 * declarations -> 
 *    [CONST ID = constant';' {ID = constant';'}]
 *    [TYPE ID = type';' {ID = type';'}]
 *    [VAR idlist ':' type';' {idlist ':' type';'}]
 *    
 *
 * modules -> {procedure | function}
 * 
 * procedure -> PROCEDURE ID formalparm';' declarations stmtblock ';'  -- NAO EXISTE MAIS PROCEDURE DENTRO DE PROCEDURE
 * 
 * function -> FUNCTION ID formalparm ':' typeid ';'declarations stmtblock';' -- NAO EXISTE MAIS PROCEDURE DENTRO DE PROCEDURE
 * 
 * stmtblock -> BEGIN stmtlist END
 * 
 * stmtlist -> stmt {';' stmt}
 * 
 * stmt -> stmtblock | ifstmt | whilestmt | repstmt | forstmt | gotostmt | casestmt | idstmt
 * 
 * idstmt -> ID
 */

/** further simplifications for today only:
 * 
 * program -> PROGRAM ID ';' block '.'
 * 
 * block -> declarations stmtblock
 * 
 * declarations -> [VAR idlist ':' type';' {idlist ':' typeid';'}]
 *    modules
 *
 * modules -> {procedure | function}
 * 
 * procedure -> PROCEDURE ID formalparm';' block ';'
 * 
 * function -> FUNCTION ID formalparm ':' typeid ';'block';'
 * 
 * stmtblock -> BEGIN stmtlist END
 * 
 * stmtlist -> stmt {';' stmt}
 * 
 * stmt -> stmtblock | ifstmt | whilestmt | repstmt | idstmt | ""
 */

#include <stdio.h>
#include <string.h>

#include "parser.h"
#include "keywords.h"
#include "tokens.h"
#include "lexer.h"

#define MAXSYMLIST 0x10000
#define MAXIDSIZE 32

int sympos;
int objtype;
int acctype,returnedtype;
int symbol_entry;
int errflag;
int offset;
char symlist[MAXSYMLIST][MAXIDSIZE];
int sympos;

FILE *target;


void
myparser(void)
{
	fprintf(stderr,"Entrou em myparser\n");
	program();
}

/* 
 * program -> PROGRAM ID ';' block '.'
 */
void
program(void){
  fprintf(stderr,"Entrou em PROGRAM\n");
  if(lookahead == PROGRAM){
  //scanf("InternalTest lookahead=%s", lookahead);
  match(PROGRAM); 
  
  match(ID);
  match(';');
  }
  block();
  match('.');  
  fprintf(stderr,"\nFIM DO PROGRAMA\n");
}

/*
 * block -> declarations stmtblock
 */
void
block(void){
  declarations();stmtblock();
}

extern int symtab_nextentry;


/*
 * declarations -> [VAR idlist ':' type';' {idlist ':' type';'}] modules
 */
void
declarations(void){
  if(lookahead==VAR){
    match(VAR);
    rep_idlist:
    idlist();
    match(':');
    typeid();
    match(';');
    if(lookahead==ID) goto rep_idlist;
  }
  modules();
}

/*
 * modules -> {procedure | function}
 */
void
modules(void){
  while(lookahead == PROCEDURE || lookahead == FUNCTION){
    if(lookahead == PROCEDURE){
      procedure();
    }
    else function();
  }
}

/*
 * procedure -> PROCEDURE ID formalparm';' block ';'
 */
void
procedure(void){
  match(PROCEDURE);
  match(ID); formalparm(); match(';');
    block();
    match(';');
}



/*
 * formalparm -> '(' idlist ':' typeid {; idlist ':' typeid}  ')' ';'
 */
void
formalparm(void){
  match('(');
  idlist(); match(':'); typeid();
  while(lookahead == ';'){
    match(';');
    idlist(); match(':'); typeid();
  }
  match(')'); match(';');
}


/*
 * function -> FUNCTION ID formalparm ':' typeid ';'block';'
 */
void
function(void){
  match(FUNCTION);
  match(ID);  
  formalparm();match(':');
  int tmptype = 0;     //typheck de procedime(4);
  match(';');
  block();
  match(';');
}


/*
 * idlist -> ID {','ID}
 */
void
idlist(void){
  match(ID);
  while(lookahead==','){
    match(',');
    match(ID);
  }
}

/*
 * typeid -> INTEGER | REAL
 */
int
typeid(void){
  int dtype, i;      /** datatype **/  
  switch(lookahead){
    case INTEGER:
      match(dtype=INTEGER);
      return INTEGER;
      break;
    default:
      match(dtype=REAL);
      return REAL;
  }
}

/*
 * idstmt
 */
void
idstmt(void){

  match(ID);
  match(ASSGNMT);
  expr();
}

/*
 * stmtblock -> BEGIN stmtlist END
 */
void
stmtblock(void){
  match(BEGIN);stmtlist();match(END);
}

/*
 * stmtlist -> stmt {';'stmt}
 */
void
stmtlist(void){
  stmt();
  while(lookahead==';'){
    match(';');stmt();
  }
}

/*
 * ifstmt -> IF expression THEN stmt[ELSE stmt]
 */
void
ifstmt(void){
  match(IF); expression(); match(THEN);
  stmt();
  if(lookahead==ELSE) {
    match(ELSE);stmt();
  }
}


/*
 * whilestmt -> WHILE DO stmt
 */
void
whilestmt(void){
  match(WHILE);expression();match(DO);
  stmt();
}


/*
 * repstmt -> REPEAT stmtlist UNTIL expression
 */
void
repstmt(void){
  match(REPEAT);
  stmtlist();
  match(UNTIL);
  expression();
}


/*
 * forstmt-> FOR assign [TO|DOWNTO] expression DO stmt
 */
void
forstmt(void){
  match(FOR);
  assign();
  if (lookahead==TO){
    match(TO);
  }
  else{
    match(DOWNTO);
    expression();
    match(DO);
    stmt();
  }
}


/*
 * stmt -> stmtblock | ifstmt | whilestmt | repstmt | idstmt | ""... complementar
 */
void
stmt(void){
  switch(lookahead){
    case BEGIN:
      stmtblock();
      break;
    case IF:
      ifstmt();
      break;
    case WHILE:
      whilestmt();
      break;
    case REPEAT:
      repstmt();
      break;
    case ID:
      idstmt();
      break;
  }
}


/*
 * gotostm -> GOTO UINT
 */

/*
 * void gotostmt(void){
 *    match('GOTO'); match('UINT');
 }
 */


/*
 * isrelationalop -> '=' | '>' | '=' | '>' | '<' | GEQ | LEQ | NEQ
 */
isrelationalop(token_t token){
  switch(token){
    case '=':
    case '>':
    case '<':
    case GEQ:
    case LEQ:
    case NEQ:
      return token;
  }
  return 0;
}


/*
 * isaddop-> '+' |'-' | OR
 */
isaddop(token_t token){
  switch(token){
    case '+':
      return 1;
      break;
    case '-':
      return 1;
      break;
    case OR:
      return 1;
      break;
    default:
      return 0;
  }
  
}


/*
 * ismulop -> '*' | '/' | AND | DIV | MOD
 */
ismulop(token_t token){
  switch(token){
    case '*':
      return 1;
      break;
    case '/':
      return 1;
      break;
    case AND:
      return 1;
      break;
    case DIV:
      return 1;
      break;
    case MOD:
      return 1;
      break;
    default:
      return 0;
      
  }
  
}

/*
 * expression-> expr [isrelationalop expr]
 */
void
expression(void){
  expr();
  if(isrelationalop(lookahead)){   /* VAMOS ADMITIR QUE SEJA POSSIVEL COMPARAR INTEIRO COM PONTO FLUTUANTE*/
    match(lookahead); expr();      /* AQUI TERA QUE SER UMA VARIAVEL LOGICA*/
  }
}

/*
 * expr-> [-] term {isaddop term}
 */
void
expr(void){
  int ex=0;
  if(lookahead=='-'){
    match('-');
  }
  term();
  while(lookahead==OPLUS){
    match(lookahead); term();
  }
}

/*
 * term-> factor {ismulop factor}
 */
void
term(void){
  int op;
  factor();
  while(lookahead==OTIMES){
    op = lookahead;
    match(lookahead);
    factor();
  }
}


/*
 * factor-> UINT | FLOAT | ID ['=' expr] |'(' exprlist ')'| NOT factor
 */
void
factor(void){  
  switch(lookahead){
    case UINT:
      match(UINT);
      break;
    case FLOAT:
      match(FLOAT);
      break;
    case ID:
      match(ID);
      if(lookahead=='('){
	match('(');exprlist();match(')');
      }
      break;
    case '(':
      match('('); expression(); match(')');     /* SE RETURNED TYPE FOR LÃ“GICO, O ACCTYPE SO PODE SER LOGICO */
      /** at this point, expression has synthesized an attribute storing resulting data type in the expression. However, the just calculated attribute might be grater than the Left-attribute along the current expression, so that a promotion must accur (tipo int Ã© menos complexo que ponto flutuante) 
       *	ISSO VAI ACOTECER TAMBÃ‰M PARA INTEIRO SEM SINAL, "PROMOCAO DE TIPO" **/
      break;
      
    default:
      match(NOT);factor();  /* PRECISA DE PONTO FLUTUANTE, SE APARECER UMA EXPRESSAO ARITMETICA NÃƒO PODE AFIRMAR NADA, SO NO FINAL DO FATOR SABEREMOS SE O TIPO RETORNADO Ã‰ LOGICO*/
  }
}


/*
 * exprlist-> expression {',' expression}
 */
void
exprlist(void){
  expression();
  while(lookahead==','){
    match(',');expression();
  }
}